package com.dodo.blog.ui.ajax;

import com.dodo.blog.RequestCycle;
import com.dodo.blog.ui.ajax.annotation.SetModel;
import com.dodo.blog.ui.page.Page;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.groups.Default;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @author <a href="mailto:pohorelec@comvai.com">Jozef Pohorelec</a>
 */
public class FormPostAjaxRequestHandler
        extends AbstractAjaxRequestHandler
{
    private static final long serialVersionUID = 1L;

    @Override
    public void handle() throws Exception
    {
        HttpServletRequest httpRequest = RequestCycle.get().getRequest();
        HttpServletResponse httpResponse = RequestCycle.get().getResponse();

        String modelId = httpRequest.getParameter( AjaxListenerHelper.PARAM_MODEL_ID );
        if ( modelId != null )
        {
            Page page = RequestCycle.get().getInjector().getInstance( getPageClass() );

            // check model parameter
            String modelParameter = httpRequest.getParameter( AjaxListenerHelper.PARAM_METHOD_MODEL );
            if ( modelParameter == null )
            {
                log.severe( "Model parameter ['" + AjaxListenerHelper.PARAM_METHOD_MODEL + "'] must be set." );
                return;
            }

            // check json parameter
            String jsonParameter = httpRequest.getParameter( AjaxListenerHelper.PARAM_JSON );
            if ( jsonParameter == null )
            {
                log.severe( "Json parameter ['" + AjaxListenerHelper.PARAM_JSON + "'] must be set." );
                return;
            }

            // set model class form model parameter
            Class<?> modelClass = Class.forName( modelParameter );
            for ( Method method : page.getClass().getDeclaredMethods() )
            {
                SetModel setModelAnnotation = method.getAnnotation( SetModel.class );
                if ( setModelAnnotation != null && setModelAnnotation.name().equals( modelId ) )
                {
                    // parse json parameter into model object
                    Object model = getModelObject( page, modelId );
                    MAPPER.updatingReader( model ).readValue( jsonParameter );

                    try
                    {
                        Response response = ( Response ) method.invoke( page, model );
                        response.setMessages( RequestCycle.get().getMessages() );
                        response.setModel( model );
                        httpResponse.getWriter().write( MAPPER.writeValueAsString( response ) );
                    }
                    catch ( InvocationTargetException e )
                    {
                        throw ( Exception ) e.getCause();
                    }
                    return;
                }
            }

            log.severe( "No method with annotation " + SetModel.class.getName() + "(name = '" + modelId + "') found in class " + page.getClass().getName() );
        }
    }

    private Class[] getValidationGroups( String groups )
    {
        if ( StringUtils.isBlank( groups ) )
        {
            return new Class[]{Default.class};
        }

        List<Class> groupList = new ArrayList<Class>();
        for ( String group : groups.split( "," ) )
        {
            try
            {
                groupList.add( Class.forName( group ) );
            }
            catch ( ClassNotFoundException e )
            {
                log.warning( "No class found for validation group: " + group );
            }
        }

        return groupList.toArray( new Class[]{} );
    }
}
